﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using ARCam3D.Camera;
using ARCam3D.Imaging;
using ARCam3D.Imaging.Processing;
using ARCam3D.Tuple;
using ARCam3D.Transform;

namespace ARCam3D.UI.Forms
{
    public partial class MainForm : Form
    {
        AboutForm aboutForm = new AboutForm();
        private CameraInfo cameraInfo = new CameraInfo(640, 480, 53.13 * Math.PI / 180);
        private CameraProjectionTransform cameraProjectionTransform;
        private MarkerDetector markerDetector;

        public MainForm()
        {
            InitializeComponent();
            this.Text = Program.AssemblyTitle;
            deviceComboBox.Items.AddRange(Grabber.GetDevices());

            cameraProjectionTransform = new CameraProjectionTransform(cameraInfo);
            markerDetector = new MarkerDetector(cameraProjectionTransform, 0.1);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (grabberWorker.IsBusy)
            {
                grabberWorker.CancelAsync();
                e.Cancel = true;
            }
        }

        private void showHelpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FileInfo fileInfo = new FileInfo(Application.ExecutablePath);
            System.Diagnostics.Process.Start(fileInfo.DirectoryName + "\\help\\index.html");
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            aboutForm.ShowDialog();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void grabberWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            grab();
        }

        private void grabberWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Close();
        }

        private void selectDeviceButton_Click(object sender, EventArgs e)
        {
            if (deviceComboBox.SelectedIndex < 0) return;

            deviceComboBox.Enabled = false;
            selectDeviceButton.Enabled = false;
            saveImageButton.Enabled = true;
            grabberWorker.RunWorkerAsync();
        }

        private void grab()
        {
            int deviceIndex = 0;
            this.Invoke(() =>
            {
                deviceIndex = deviceComboBox.SelectedIndex;
            });

            Grabber grabber = new Grabber(deviceIndex);
            grabber.Start();
            
            Queue<double> fpsQueue = new Queue<double>();

            while (!grabberWorker.CancellationPending)
            {
                DateTime start = DateTime.Now;

                grabber.WaitForNewImage();
                RGBImage image = grabber.GetImage();

                Point2I[] markerCorners = markerDetector.FindMarkerCorners(image);

                MatrixTransform3D transform = null;
                if (markerCorners != null)
                {
                    transform = markerDetector.GetMarkerTransform(image, markerCorners);

                }

                fpsQueue.Enqueue(1000d / DateTime.Now.Subtract(start).TotalMilliseconds);
                if (fpsQueue.Count > 80) fpsQueue.Dequeue();

                double fpsAverage = 0;
                foreach (double fps in fpsQueue) fpsAverage += fps;
                fpsAverage /= fpsQueue.Count;

                this.BeginInvoke(() =>
                {
                    graphicsControl.SetCameraImage(image);
                    graphicsControl.SetMarkerTransform(transform);
                    //graphicsControl.Invalidate();
                    fpsLabel.Text = fpsAverage.ToString("0.0");
                });
            }

            grabber.Stop();
        }

        public object Invoke(MethodInvoker invoker)
        {
            return this.Invoke((Delegate)invoker);
        }

        public IAsyncResult BeginInvoke(MethodInvoker invoker)
        {
            return this.BeginInvoke((Delegate)invoker);
        }

        private void loadModelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openModelDialog.ShowDialog() == DialogResult.OK)
            {
                FileInfo fileInfo = new FileInfo(openModelDialog.FileName);
                graphicsControl.SetModel(fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf('.')));

            }
        }

        private void saveImageButton_Click(object sender, EventArgs e)
        {
            Bitmap bitmap = graphicsControl.GetImage();
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {


                bitmap.Save(saveFileDialog.FileName);
            }
        }
    }
}
